﻿// ===============================================================================
// MatchingRoute.cs
// EOS Web Framework
// ===============================================================================
// Copyright (c) EOS Development Group. All rights reserved.
// ===============================================================================

namespace EOS.Framework.Contracts.Web.Routing
{
    using System;
    using System.Globalization;
    using System.Diagnostics.CodeAnalysis;
    using EOS.Framework.Tools;

    /// <summary>
    /// Wrapps all values from a matching route.
    /// </summary>
    [Serializable]
    public class MatchingRoute : IEquatable<MatchingRoute>
    {
        #region Properties

        /// <summary>
        /// The url of the best matching route.
        /// </summary>
        private string _url;

        /// <summary>
        /// Gets or sets the url of the best matching route.
        /// </summary>
        /// <value>The url of the best matching route.</value>
        [SuppressMessage("Microsoft.Design", "CA1056", Justification = "Uri class cannot handle this kind of urls")]
        public string Url
        {
            get { return _url; }
            set { _url = value; }
        }
        
        /// <summary>
        /// Reference to the handler, which has to handle the request to the current url.
        /// </summary>
        private IRouteHandler _handler;

        /// <summary>
        /// Gets or sets the handler.
        /// </summary>
        /// <value>Reference to the handler, which has to handle the 
        /// request to the current url. Cannot be null (Nothing in Visual Basic).</value>        
        /// <exception cref="ArgumentNullException"><paramref name="value"/> is null 
        /// (Nothing in Visual Basic).</exception>
        public IRouteHandler Handler
        {
            get { return _handler; }
            set { _handler = value; }
        }
        
        /// <summary>
        /// All parameters, extracted from the url.
        /// </summary>
        private RouteValueDictionary _parameters;

        /// <summary>
        /// Gets or sets the parameters extracted from the url.
        /// </summary>
        /// <value>The parameters. Cannot be null (Nothing in Visual Basic).</value>        
        /// <exception cref="ArgumentNullException"><paramref name="value"/> is null 
        /// (Nothing in Visual Basic).</exception>
        public RouteValueDictionary Parameters
        {
            get
            {
                if (_parameters == null)
                {
                    _parameters = new RouteValueDictionary();
                }
                return _parameters;
            }
        }

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="MatchingRoute"/> class.
        /// </summary>
        public MatchingRoute()
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="MatchingRoute"/> class with
        /// the url, the parameters and a reference to the handler.
        /// </summary>
        /// <param name="url">The URL. Cannot be null or a string of length 0.</param>
        /// <param name="parameters">The parameters for the route.</param>
        /// <param name="handler">The route handler, which handles the request.</param>
        [SuppressMessage("Microsoft.Design", "CA1054", Justification = "Uri class cannot handle this kind of urls")]
        public MatchingRoute(string url, RouteValueDictionary parameters, IRouteHandler handler)
        {
            this._url = url;
            this._handler = handler;
            this._parameters = parameters;
        }

        #region IEquatable<MatchingRoute> Members

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> 
        /// is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to 
        /// compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is 
        /// equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            return Equals(obj as MatchingRoute);
        }

        /// <summary>
        /// Indicates whether the current object is equal to 
        /// another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// true if the current object is equal to the <paramref name="other"/> 
        /// parameter; otherwise, false.
        /// </returns>
        public bool Equals(MatchingRoute other)
        {
            if (other == null)
            {
                return false;
            }

            bool result = true;

            if (result && !Object.Equals(_handler, other._handler))
            {
                result = false;
            }

            if (result && !Object.Equals(_url, other._url))
            {
                result = false;
            }

            if (result && !Extensions.IsEqual(_parameters, other._parameters))
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            int hashCode = 1;
            
            if (_handler != null)
            {
                hashCode ^= _handler.GetHashCode();
            }
            if (_url != null)
            {
                hashCode ^= _url.GetHashCode();
            }
            if (_parameters != null)
            {
                hashCode ^= _parameters.CreateHashCode();
            }
            
            return hashCode;
        }

        #endregion
    }
}
